package wci.frontend.pascal;

import static wci.message.MessageType.PARSER_SUMMARY;

import java.io.IOException;
import java.util.EnumSet;

import wci.frontend.EofToken;
import wci.frontend.Parser;
import wci.frontend.Scanner;
import wci.frontend.Token;
import wci.frontend.TokenType;
import wci.frontend.pascal.parsers.StatementParser;
import wci.intermediate.ICode;
import wci.intermediate.ICodeFactory;
import wci.intermediate.ICodeNode;
import wci.intermediate.SymTabEntry;
import wci.message.Message;

/**
 * <h1>PascalParserTD</h1>
 * 
 * <p>
 * Top-Down模式的Pascal Parser，Pascal解析器的基类
 * </p>
 * <p>
 * Copyright (c) 2009 by Ronald Mak<br>
 * For instructional purposes only. No warranties.
 * </p>
 */
public class PascalParserTD extends Parser {

	protected PascalErrorHandler errorHandler = new PascalErrorHandler();

	public PascalParserTD(Scanner scanner) {
		super(scanner);
	}

	/* 新增链条解析(Parser Chain) */
	public PascalParserTD(PascalParserTD parent) {
		super(parent.getScanner());
	}

	/**
	 * Pascal的解析过程，产生Pascal相关的iCode和symbol table
	 */
	public void parse() throws Exception {

		long startTime = System.currentTimeMillis();
		iCode = ICodeFactory.createICode();
		try {
			Token token = nextToken();
			ICodeNode root_node = null;
			if (token.getType() == PascalTokenType.BEGIN) {
				// 前探到一个最外部的复合语句
				StatementParser default_parser = new StatementParser(this);
				// 解析begin XXXXX end. 中的内容XXXXX，并吞噬掉end
				root_node = default_parser.parse(token);
				token = currentToken(); // 指向end. 中的.
			} else {
				// 每个Pascal程序必须以begin开头，end. 结束
				errorHandler
						.flag(token, PascalErrorCode.UNEXPECTED_TOKEN, this);
			}
			if (root_node != null) {
				iCode.setRoot(root_node);
			}
			// 最后的.存在么？
			if (token.getType() != PascalTokenType.DOT) {
				errorHandler.flag(token, PascalErrorCode.MISSING_PERIOD, this);
			}
			token = currentToken(); // 没意义，不过我还是放在这，尊重作者。
			// 发送编译摘要信息
			float elapsedTime = (System.currentTimeMillis() - startTime) / 1000f;
			sendMessage(new Message(PARSER_SUMMARY, new Number[] {
					token.getLineNumber(), getErrorCount(), elapsedTime }));
		} catch (IOException e) {
			errorHandler.abortTranslation(PascalErrorCode.IO_ERROR, this);
		}
	}

	public int getErrorCount() {
		return errorHandler.getErrorCount();
	}
	/**
	 * 同步解析器的当前token到集合所允许的Token
	 * @param syncSet 下一步有效的token集合
	 * @return 找到的某个有效的token
	 * @throws Exception
	 */
	public Token synchronize(EnumSet syncSet) throws Exception {
		Token token = currentToken();
		//如果当前token不在同步集合里，那么就需要跳跃到结合范围内的token。
		if (!syncSet.contains(token.getType())) {
			//报告一个解析错误然后继续往前解析
			errorHandler.flag(token, PascalErrorCode.UNEXPECTED_TOKEN, this);
			do {
				token = nextToken();
			} while (!(token instanceof EofToken)
					&& !syncSet.contains(token.getType()));
		}
		return token;
	}
}
